package test.demo;

import com.alibaba.fastjson.JSON;
import tech.waterism.modelbase.PredictBase;
import tech.waterism.modelbase.PredictResult;

import java.util.*;

/**
 * 考虑损失的马斯京根河道连续演算法
 *
 * @author 初京刚
 * @version 1.0
 */
public class WJQMSK extends PredictBase {

    private Date[] TM;
    /**
     * 输入流量过程
     */
    private double[] QQi;

    private double[] QI;

    /**
     * 输出流量过程
     */
    private double[] QQo;

    private double[] Qo;

    /**
     * 马法初始流量
     */
    private double[] Qcbe;

    /**
     * 马法断面初始流量
     */
    private double[] Qc0;

    /**
     * 马法下游断面初始流量
     */
    private double[] qc;

    /**
     * 输入时段个数
     */
    private int nt;

    /**
     * 输入时段长
     */
    private double dt;

    /**
     * 时段长/h
     */
    private double tt;

    /**
     * 子河段蓄量常数
     */
    private double k1;

    /**
     * 子河段流量比重系数
     */
    private double x1;

    /**
     * 河段分段数
     */
    private int nn;

    /**
     * 演算非线性流量阈值
     */
    private double Qm;

     /**
     * 演算损失系数
     */
    private double r1;

    /**
     * 演算损失非线性流量阈值
     */
    private double Qr;

    public WJQMSK(Map<String, String> data) {
        super();
        double qim = 0.0;
        QQi = JSON.parseObject(data.get("q"), double[].class);
        for(int i = 0; i < QQi.length; i++){
            if(qim <= QQi[i]) {
                qim = QQi[i];
            }
        }
        TM = JSON.parseObject(data.get("dt"), Date[].class);             // input[i].data.dt
        if(TM.length > 1){
            dt = getHours(TM[0], TM[1]);
        }else{
            dt = Double.parseDouble(data.get("clen"));                  // index.clen
        }
        nt = QQi.length;
        QI = new double[nt];
        Qo = new double[nt];
        QQo = new double[nt];
        Qcbe = new double[2];
        tt = Double.parseDouble(data.get("KK"));
        k1 = Double.parseDouble(data.get("k"));
        x1 = Double.parseDouble(data.get("X1"));
        nn = Integer.parseInt(data.get("n1"));
        r1 = Double.parseDouble(data.get("r1"));
        Qm = Double.parseDouble(data.get("Qm"));
        Qr = Double.parseDouble(data.get("Qr"));
        if(qim > Qm) {
            x1 = Double.parseDouble(data.get("X2"));
            nn = Integer.parseInt(data.get("n2"));
        }
        if(qim > Qr) {
            r1 = Double.parseDouble(data.get("r2"));
        }
        for(int i = 0; i < nt; i++) {
            QI[i] = QQi[i];
        }
        // 判定一下
        if(QI.length > 1){
            Qcbe[0] = QI[1];
            Qcbe[1] = QI[1];
        }else{
            Qcbe[0] = QI[0];
            Qcbe[1] = QI[0];
        }
    }

    /**
     * 模型计算
     */
    public Map<String, double[]> WJQMSKmodel() {

        // 河道演进
        wjqmuskingumSeg();
        for (int i = 0; i < nt; i++) {
            QQo[i] = Qo[i] * r1;
        }
        Map<String, double[]> simulationResult = new HashMap<>();
        simulationResult.put("Q", QQi);
        simulationResult.put("QSim", QQo);
        return simulationResult;
    }

    /**
     * 河道演进-分段马斯京根
     *
     * @return 河道演进-单元面积出口流量（m3/s）
     */
    private void wjqmuskingumSeg() {
        if(nn == 0) {
            for(int i = 0; i < nt; i++) {
                Qo[i] = QI[i];
            }
        } else {
            double nn1 = nn * tt / dt; //时段转换，先转成分段nn之后的总数，再按输入时段长dt转换
            if(nn1 < 1.001) {
                nn1 = 1.001;
            }
            double kk1 = nn * k1 / nn1; //时段转换，先转成分段nn之前的，再按输入分段数nn1转换
            double XX = 0.5 -0.5 * (1.0 - 2.0 * x1) / nn; //时段转换，先转成分段之前的
            double xx1 = 0.5 - 0.5 * nn1 * (1.0 - 2.0 * XX); //再按输入分段数转换

            int n = (int)nn1;
            XX = kk1 - kk1 * xx1 + 0.5 * dt;
            double C10 = (0.5 * dt - kk1 * xx1) / XX;
            double C11 = (0.5 * dt + kk1 * xx1) / XX;
            double C12 = (kk1 - 0.5 * dt - kk1 * xx1) / XX;
            Qc0 = new double[n + 1];
            qc = new double[n + 1];

            for(int i = 0; i < n + 1; i++){
                Qc0[i] = Qcbe[0] + i * (Qcbe[1] - Qcbe[0]) / n;
            }

            for(int i = 1; i < n + 1; i++) {
                qc[i] = Qc0[i - 1] * 0.5 + Qc0[i] * 0.5;
            }
            Qo[0] = qc[n];

            for(int i = 1; i < nt; i++) {
                double QQi = QI[i - 1] * 0.5 + QI[i] * 0.5;
                double C0 = C10;
                double C1 = C11;
                double C2 = C12;
                double QI1 = 0.0;
                double QI2 = 0.0;
                double QO1;
                double QO2 = 0.0;
                for(int j = 1; j < n + 1; j++){
                    QO1 = qc[j];
                    if(j == 1) {
                        QI1 = QI[i - 1];
                        QI2 = QI[i];
                    }
                    QO2 = C0 * QI2 + C1 * QI1 + C2 * QO1;
                    QI1 = QO1;
                    QI2 = QO2;
                    qc[j] = QO2;
                }
                Qo[i] = QO2;
            }

        }
        //        double[] QC = new double[Qr.length];
    }

    @Override
    public void init() {

    }

    @Override
    public PredictResult predict() {
        PredictResult result = new PredictResult();
        Map<String, double[]> map = WJQMSKmodel();

        result.setQSim(map.get("QSim"));

        double[] QSim = map.get("QSim");

        for (int i = 0; i < QSim.length; i++) {
            System.out.println(QSim[i]);
        }
        return result;
    }

    public int getHours(Date dt_beg, Date dt_end) {
        int hours = -1;
        hours = Long.valueOf((dt_end.getTime() - dt_beg.getTime()) / (3600 * 1000L)).intValue();
        return hours;
    }
}